<template>
    <div v-loading="loading">
      <div style="margin-bottom: 16px">
        <div style="display: flex; justify-content: space-between;height:34px;position:relative;">
          <el-space wrap v-if="operating">
            <el-switch v-model="collapse" @change="changeSwitch" />折叠行
            <el-button type="primary"  @click="addTask()">新建节点</el-button>
            <el-button :disabled="checkList.length === 0" type="primary"
              @click="addLinks()">建立连接</el-button>
            <el-button :disabled="checkList.length === 0" type="danger"
              @click="deleteTasks()">删除</el-button>
            <el-button type="primary" :disabled="undoDisabled"
              @click="undoAction()">后退</el-button>
            <el-button type="primary" :disabled="redoDisabled"
              @click="ReDoAction()">前进</el-button>
            <el-button :disabled="checkList.length === 0" type="primary"
              @click="checkAction('indent')">升级</el-button>
            <el-button :disabled="checkList.length === 0" type="primary"
              @click="checkAction('outdent')">降级</el-button>
            <el-button :disabled="checkList.length !== 1" type="primary"
              @click="addAction('insert')">插入</el-button>
            <el-button :disabled="checkList.length !== 1" type="primary"
              @click="addAction('copy')">复制</el-button>
            &nbsp;
          </el-space>
          <div style="position:absolute;right:2%;top:13%;">
            <el-button-group class="ml-4">
              <el-button :type="scaleUnitModal === 'year' ? 'primary' : ''" @click="changeUnit('year')">年</el-button>
              <el-button :type="scaleUnitModal === 'month' ? 'primary' : ''" @click="changeUnit('month')">月</el-button>
              <el-button :type="scaleUnitModal === 'day' ? 'primary' : ''" @click="changeUnit('day')">日</el-button>
              <el-button :type="scaleUnitModal === 'hour' ? 'primary' : ''" @click="changeUnit('hour')">小时</el-button>
            </el-button-group>
          </div>
        </div>
      </div>
      <div style="display:flex;height:98%">
        <div @click="closeGrid()">
          <el-icon color="#409efc" size="30">
            <Fold v-if="!gridShow" />
            <Expand v-else />
          </el-icon>
        </div>
        <div id="ganttId" class="gantt_task" ref="ganttRef" style="width: 98%; height: 760px"></div>
      </div>
    </div>
  </template>
  
  <script setup lang="tsx" name="Gantt">
  import { onMounted, ref, onBeforeUnmount, render } from 'vue';
  import { gantt } from 'dhtmlx-gantt' // 引入模块
  import './gantt.scss';
// 推测 `/@` 是路径别名，通常在 Vue 项目里对应 `src` 目录，将其替换为 `src` 或者检查项目配置确认正确别名
import { generateUUID } from '@/utils/other';
  import { ElMessage } from 'element-plus';
  const props = defineProps({
    operating: {
      type: Boolean,
      default: false
    },
    taskData: {
      type: Object,
      default: () => {
        return {
          data: [], // 数据数组
          links: [], // 连接关系
        };
      },
    },
    // 时间显示格式
    editType: {
      type: String,
      default: 'day', // “minute”, “hour”, “day”, “week”, “quarter”, “month”, “year”
    },
    // 当前网络计划的状态
    planStatus: {
      type: String,
      default: '0',
    },
  });
  const ganttRef = ref();
  const gridShow = ref(true);
  const checkList = ref([]);
  const scaleUnitModal = ref('day');
  const isNotReset = ref(false);
  const loading = ref(false);
  const collapse = ref(true); // 控制tree的展开折叠
  const undoDisabled = ref(false);
  const redoDisabled = ref(false);
  const existEditType = ref('') as any;
  const scrollTop = ref(0);
  const openTasks = ref([]);
  const actions = {
    indent: function indent(task_id) {
      // 增加任务的层级，即将任务嵌套在另一个任务之下，使其成为一个子任务
      var prev_id = gantt.getPrevSibling(task_id);
      while (gantt.isSelectedTask(prev_id)) {
        var prev = gantt.getPrevSibling(prev_id);
        if (!prev) break;
        prev_id = prev;
      }
      if (prev_id) {
        var new_parent = gantt.getTask(prev_id);
        gantt.moveTask(task_id, gantt.getChildren(new_parent.id).length, new_parent.id);
        new_parent.type = gantt.config.types.project;
        new_parent.$open = true;
        gantt.updateTask(task_id);
        gantt.updateTask(new_parent.id);
        return task_id;
      }
      return null;
    },
    outdent: function outdent(task_id, initialIndexes, initialSiblings) {
      // // 减少任务的层级，有父级的任务
      var cur_task = gantt.getTask(task_id);
      var old_parent = cur_task.parent;
      // gantt.isTaskExists(old_parent) 检查任务是否存在，存在返回true，不存在返回false
      if (gantt.isTaskExists(old_parent) && old_parent != gantt.config.root_id) {
        var index = gantt.getTaskIndex(old_parent) + 1;
        var prevSibling = initialSiblings[task_id].first;
  
        if (gantt.isSelectedTask(prevSibling)) {
          index += (initialIndexes[task_id] - initialIndexes[prevSibling]);
        }
        gantt.moveTask(task_id, index, gantt.getParent(cur_task.parent));
        if (!gantt.hasChild(old_parent))
          gantt.getTask(old_parent).type = gantt.config.types.task;
        gantt.updateTask(task_id);
        gantt.updateTask(old_parent);
        return task_id;
      }
      return null;
    },
    del: function (task_id) {
      if (gantt.isTaskExists(task_id)) gantt.deleteTask(task_id);
      return task_id;
    },
  };
  onMounted(() => {
    scaleUnitModal.value = props.editType;
    existEditType.value = props.editType
    // console.log('甘特图数据===', props.taskData)
    getGanttInfo()
  })
  // vue3检查一个变量是否为有效的 VNode
  const isValidVNode = (value) => {
    return typeof value === 'object' && value !== null && '__v_isVNode' in value;
  };
  const getGanttInfo = () => {
    // 清空之前的配置
    gantt.clearAll();
    // console.log('props.planStatus', props.planStatus)
    // 配置基本属性
    props.operating ? gantt.config.readonly = false : gantt.config.readonly = true;
    gantt.attachEvent("onTaskDblClick", function (id, e) { return false }); // 禁止点击进行弹窗
    gantt.templates.grid_row_class = function (start, end, task) {
      return gantt.hasChild(task.id) ? "gantt_parent_row" : "";
    };
    gantt.attachEvent("onGanttScroll", function (left, top) {
      if (top === 0) {
        return false
      } else {
        scrollTop.value = top
      }
    });
    gantt.attachEvent("onTaskOpened", function (id) {
      openTasks.value.push(id)
    });
    gantt.attachEvent("onTaskClosed", function (id) {
      openTasks.value.map((item, index) => {
        if (item == id) {
          openTasks.value.splice(index, 1)
        }
      })
    });
    gantt.i18n.setLocale('cn'); // 设置 Gantt 图的界面语言为中文
    gantt.config.show_grid = true; // 显示 Gantt 图中的网格线
    gantt.config.grid_width = 900;
    gantt.config.show_unscheduled = false;
    gantt.config.grid_elastic_columns = true;
    gantt.config.details_on_create = false; // 点击+时关闭灯箱弹窗
    gantt.config.fit_tasks = true; // 自动延长时间刻度
    // setLayout()
    // 配置外部渲染,使用onrender时的渲染方式
    gantt.config.external_render = {
      isElement: (element) => {
        return isValidVNode(element);
      },
      renderElement: (element, container) => {
        render(element, container);
      },
    };
  
    // 配置刻度单位
    // gantt.config.scale_unit = props.editType;
    setUnit(props.editType); // 甘特图刻度配置
    gantt.config.duration_unit = props.editType;
    if (props.editType === 'day') {
      gantt.config.time_step = 10; // 时间轴上的每个刻度间隔为 10 天
    }
    gantt.config.step = 1; // 设置步长为 1
    gantt.config.scale_height = 28 * 3; // 甘特图的时间刻度高度
    gantt.config.min_column_width = 16;
    gantt.config.duration_step = 1; // 任务持续时间步长
    gantt.config.redo = true; // 重做功能
    gantt.config.undo = true; // 启用撤销功能
    gantt.config.order_branch = 'marker'; // 左侧树型结构调整时，只允许将任务拖放到某个父节点下
    gantt.config.order_branch_free = true; // 左侧树型结构调整时，可以任意拖动任务到任意节点下
    gantt.config.auto_scheduling = true; // 控制任务是否自动重新安排
    gantt.config.show_errors = false; // 发生异常时，不允许弹出警告到 UI 界面
  
    // 初始化扩展设置
    props.planStatus === '0' ? setGanttColumn() : resetGanttColumn(); // 配置甘特图右侧表格
    // initExtensions(); 初始化扩展设置
    addTaskType(); // 添加任务类型
  
    // 插件配置
    gantt.plugins({
      tooltip: true, // 设置工具提示
      quick_info: false, // 快速信息框进行隐藏
      export_api: true, // 导出 API
      undo: true, // 启用撤销功能
      marker: true, // 标记
      auto_scheduling: true, // 控制任务是否自动重新安排
    });
  
    // 添加今天的标记
    addTodayMarker();
    addProjectStartMarker()
  
    // 展开或折叠树形结构
    if (collapse.value) {
      expandAll();
    } else {
      collapseAll();
    }
    // 初始化甘特图
    gantt.init(ganttRef.value);
    gantt.parse(props.taskData);
    gantt.render();
    onTaskChange();
  };
  
  // 甘特图列配置
  const setGanttColumn = () => {
    customEditor()
    const textEditor = { type: 'text', map_to: 'text' }
    const startDateEditor = { type: 'date', map_to: 'start_date' }
    const endDateEditor = { type: 'date', map_to: 'end_date' }
    const adjustFinishTimeEditor = { type: 'date', map_to: 'adjustFinishTime' }
    const numberEditor = { type: 'number', map_to: 'progress', min: 0, max: 100 }
    const durationEditor = { type: 'number', map_to: 'duration', min: 1 }
    const predecessorEditor = { type: "predecessor", map_to: "auto" }
    const statueEditor = { type: "status_editor", map_to: "status" }
    gantt.config.columns = [  // 配置表头
      { align: 'center', name: 'add', label: '', width: 30 },
      {
        align: 'center',
        name: 'buttons',
        label: '选择',
        width: 35,
        onrender: (task: any, node: HTMLInputElement) => {
          let input = document.createElement('INPUT');
          input.setAttribute('type', 'checkbox');
          input.setAttribute('style', 'height:35px;width: 20px');
          input.setAttribute('id', 'checkbox' + (task.type !== undefined ? task.type : '') + task.id);
          const findIndex = checkList.value.findIndex((c: String) => c + '' === task.id + '');
          if (findIndex > -1) {
            input.checked = true
          }
          node.firstElementChild?.appendChild(input);
          input.onclick = handleCheckboxChange;
          return node;
        },
      },
      {
        align: 'center',
        name: 'index',
        label: '序号',
        width: 45,
        // resize: true,
        template(task) {
          // return gantt.getGlobalTaskIndex(task.id) + 1;
          return gantt.getWBSCode(gantt.getTask(task.id))
        },
      },
      {
        name: "text", label: "任务名称", align: "left", tree: true, width: 400, editor: textEditor,
        // template(task) {
        //   return "<div :title=" + task.text + "><span title='322323232332'></span>" + task.text !== undefined ? task.text : '新任务' + "</div>"
        // },
        onrender: (item, node) => {
          node.setAttribute("title", item.text);
          // console.log('node', node)
          // node.innerHTML = item.text !== undefined ? item.text : '新任务'
          return node;
        }
      },
      {
        name: "start_date", label: "预计开始时间", align: "center", width: 250, editor: startDateEditor
      },
      { name: "end_date", label: "预计完成时间", align: "center", width: 250, editor: endDateEditor },
      { name: "adjustFinishTime", label: "调整完成时间", align: "center", width: 250, editor: adjustFinishTimeEditor },
      {
        align: 'center',
        name: 'duration',
        label: '工期',
        width: 90,
        editor: durationEditor
      },
      {
        align: 'center',
        name: 'sno',
        label: '前置任务',
        width: 90,
        editor: predecessorEditor,
        template: function (task) {
          // console.log('前置任务', task)
          return getPredecessor(task)
        },
      },
      {
        name: "remark", label: "备注", align: "center"
      },
      {
        name: "status", label: `状态`, align: "center", editor:statueEditor
      },
    ];
  }
  // 审核列表
  const resetGanttColumn = () => {
    customEditor()
    const adjustFinishTimeEditor = { type: 'date', map_to: 'adjustFinishTime' }
    const statueEditor = { type: "status_editor", map_to: "status" }
    gantt.config.columns = [  // 配置表头
      { align: 'center', name: 'add', label: '', width: 30 },
      {
        align: 'center',
        name: 'buttons',
        label: '选择',
        width: 35,
        onrender: (task: any, node: HTMLInputElement) => {
          let input = document.createElement('INPUT');
          input.setAttribute('type', 'checkbox');
          input.setAttribute('style', 'height:35px;width: 20px');
          input.setAttribute('id', 'checkbox' + (task.type !== undefined ? task.type : '') + task.id);
          const findIndex = checkList.value.findIndex((c: String) => c + '' === task.id + '');
          if (findIndex > -1) {
            input.checked = true
          }
          node.firstElementChild?.appendChild(input);
          input.onclick = handleCheckboxChange;
          return node;
        },
      },
      {
        align: 'center',
        name: 'index',
        label: '序号',
        width: 45,
        // resize: true,
        template(task) {
          // return gantt.getGlobalTaskIndex(task.id) + 1;
          return gantt.getWBSCode(gantt.getTask(task.id))
        },
      },
      {
        name: "text", label: "任务名称", align: "left", tree: true, width: 400,
        // template(task) {
        //   return "<div :title=" + task.text + "><span title='322323232332'></span>" + task.text !== undefined ? task.text : '新任务' + "</div>"
        // },
        onrender: (item, node) => {
          node.setAttribute("title", item.text);
          // console.log('node', node)
          // node.innerHTML = item.text !== undefined ? item.text : '新任务'
          return node;
        }
      },
      {
        name: "start_date", label: "预计开始时间", align: "center", width: 250
      },
      { name: "end_date", label: "预计完成时间", align: "center", width: 250 },
      { name: "adjustFinishTime", label: "调整完成时间", align: "center", width: 250, editor: adjustFinishTimeEditor },
      {
        align: 'center',
        name: 'duration',
        label: '工期',
        width: 90,
      },
      {
        align: 'center',
        name: 'sno',
        label: '前置任务',
        width: 90,
        template: function (task) {
          // console.log('前置任务', task)
          return getPredecessor(task)
        },
      },
      {
        name: "remark", label: "备注", align: "center"
      },
      {
        name: "status", label: `状态`, align: "center", editor:statueEditor
      },
    ];
  }
  // 显示隐藏网格线
  const closeGrid = () => {
    if (gridShow.value) {
      gantt.config.show_grid = false; // 显示 Gantt 图中的网格线
      gantt.config.grid_width = 0;
    } else {
      gantt.config.show_grid = true; // 显示 Gantt 图中的网格线
      gantt.config.grid_width = 900;
    }
    gantt.resetLayout();
    gridShow.value = !gridShow.value
  };
  // 添加标记，表示项目的开始时间
  function addProjectStartMarker() {
    if (props.taskData.data.length > 0) {
      var earliestStartDate = new Date(props.taskData.data[0].start_date); // 初始化最早的开始时间为第一个任务的开始时间
      // 遍历所有任务，更新最早的开始时间
      for (var i = 1; i < props.taskData.data.length; i++) {
        var taskStartDate = new Date(props.taskData.data[i].start_date);
        if (taskStartDate < earliestStartDate) {
          earliestStartDate = taskStartDate;
        }
      }
      gantt.addMarker({
        start_date: earliestStartDate,
        css: 'status_line',
        text: '项目开始时间',
      });
    }
  
  }
  
  // 添加今天标记
  function addTodayMarker() {
    const todayEnd = new Date()
    var dateToStr = gantt.date.date_to_str("%F %j, %Y");
    gantt.addMarker({
      start_date: todayEnd,
      css: "today",
      text: "Today",
      title: "Today: " + dateToStr(todayEnd)
    });
  }
  // 设置甘特图不同时间刻度配置
const setUnit = (scaleUnit: any) => {
  if (scaleUnit === 'day') {
    gantt.config.scales = [
      {
        unit: 'year',
        step: 1,
        date: '%Y年',
      },
      {
        unit: 'month',
        step: 1,
        date: '%F',
      },
      {
        unit: 'day',
        step: 1,
        date: '%d',
      },
    ];
  } else if (scaleUnit === 'month') {
    gantt.config.scales = [
      { unit: "year", step: 1, format: "%Y年" },
      { unit: "month", step: 1, format: "%m月" }
    ];
  } else if (scaleUnit === 'year') {
    gantt.config.scales = [
      { unit: "year", step: 1, format: "%Y年" },
    ];
  } else if (scaleUnit === 'quarter') {
    gantt.config.scales = [
      { unit: "year", step: 1, format: "%Y年" }
    ];
  } else if (scaleUnit === 'hour') {
    gantt.config.scales = [
    { unit: "year", step: 1, format: "%Y年" },
      { unit: "day", step: 1, format: "%M %d" },
      { unit: "hour", step: 1, format: "%H" }
    ];
  }
};
const customEditor = () => {
  gantt.config.editor_types.status_editor = {
    show: function (id, column, config, placeholder) {
        const html = `<select class="form_control" ref="form_control">
            <option selected="selected">进行中</option>
            <option>已完成</option>
        </select>`;
        placeholder.innerHTML = html;
    },
    hide: function () {
        gantt.render();
    },

    set_value: function (value, id, column, node) {
        node.firstChild.value = value || "";
        // const form_control = ref()
        // console.log('form_control.value', form_control.value)
        // form_control.value.select2({
        //     tags: true
        // });
    },
    get_value: function (id, column, node) {
        return node.firstChild.value// || task.color;
    },

    is_changed: function (value, id, column, node) {
        return true;
    },

    is_valid: function (value, id, column, node) {
        return true;
    },

    save: function (id, column, node) {
    },
    focus: function (node) {
    }
  }
}
  // 改变时间单位
  const changeUnit = (value: any) => {
    scaleUnitModal.value = value;
    setUnit(value);
    // gantt.config.scale_unit = value;
    gantt.resetLayout();
  };
  // 开始时间初始化
  const startDateInit = (task: any) => {
    const links = task.$target; // 关联link的id
    let startDate = new Date()
    for (var i = 0; i < links.length; i++) {
      const link = gantt.getLink(links[i]); // 对应的关联link数据
      startDate = gantt.getTask(link.source).end_date
      task.start_date = startDate
    }
    // console.log('task.start_date', task.start_date)
    return '01-04-2025'
  }
  // 前置任务template里面的函数
  const getPredecessor = (task: any) => {
    // console.log('前置任务tsak', task)
    const labels = [];
    let links: any = [];
    // 一种找连接关系的方法
    // let alllinks = gantt.getLinks();
    // const relatedLinks = alllinks.filter(link => link.target === task.id);
    links = task.$target; // 关联link的id
    if (links.length > 0) { // 存在关联关系的
      for (var i = 0; i < links.length; i++) {
        const link = gantt.getLink(links[i]); // 对应的关联link数据
        // console.log('关联的task', link)
        // 处理没有实际完成时间的数据
        let operateTask = gantt.getTask(link.source) // 当前任务关联的上一个任务
        // console.log('当前任务关联的上一个任务',operateTask.adjustFinishTime) 
        operateTask.adjustFinishTime = operateTask.adjustFinishTime == undefined ? operateTask.end_date : operateTask.adjustFinishTime
        labels.push(gantt.getWBSCode(gantt.getTask(link.source)));
        // console.log('labels', labels.join(","))
      }
      return labels.join(",")
    } else { // 不存在关联关系的
      // console.log('关联关系link不存在', task)
      task.adjustFinishTime = task.adjustFinishTime == undefined? task.end_date : task.adjustFinishTime
      let taskIndex = gantt.getTaskIndex(task.id);
      // console.log('taskIndex', taskIndex)
      if (taskIndex && task.parent != '0') { // 存在父节点的
        let predecessorsText = gantt.getWBSCode(task).split('.')[0] + '.' + taskIndex;
        // console.log('predecessorsText', predecessorsText)
        let returnIndex = compareVersions(predecessorsText, gantt.getWBSCode(task)) ? predecessorsText : ''
        // console.log('returnIndex', returnIndex)
        const SourceTask = gantt.getTaskByWBSCode(returnIndex)
        // console.log('SourceTask', SourceTask)
        if (SourceTask !== null) {
          gantt.addLink({ source: SourceTask.id, target: task.id, type: '0' });
          task.start_date = SourceTask.end_date
          if (props.editType) { // 时间为‘day'
            let endDate = task.start_date.getTime()
            let days = task.duration * 3600000 * 24;
            task.end_date = new Date(endDate + days);
            task.adjustFinishTime = new Date(endDate + days)
          }
          return returnIndex
        } else { // 父节点下的第一个子节点
          // debugger
          // const SourceTask = gantt.getTaskByWBSCode(taskIndex + '')
          // console.log('父节点的第一个子节点', SourceTask)
          // // console.log('000', gantt.getChildren(task.id))
          // // 不存在子任务的为task
          // task.type = 'task'
        }
          
      } 
      // else if(!taskIndex && task.parent == '0'){ // 父节点且不存在上游link
      //   console.log('第一个没有涟源链接的父节点', task)
      //   const SourceTask = gantt.getTaskByWBSCode(taskIndex + '')
      //   console.log('父节点的SourceTask', SourceTask)
      //   if (props.editType) { // 时间为‘day'
      //     let endDate = task.start_date.getTime()
      //     let days = task.duration * 3600000 * 24;
      //     task.adjustFinishTime = new Date(endDate + days)
      //     console.log('前置任务渲染task.adjustFinishTime',task.end_date, task.adjustFinishTime)
      //   }
      // }
    }
  }
  // 比较序号的大小'1.9'<'1.10'
  function compareVersions(versionA, versionB) {
    // 分割字符串为数组
    let partsA = versionA.split('.');
    let partsB = versionB.split('.');
  
    // 比较每一部分
    for (let i = 0; i < Math.max(partsA.length, partsB.length); i++) {
      let numA = parseInt(partsA[i] || 0);
      let numB = parseInt(partsB[i] || 0);
  
      if (numA < numB) return true;
      if (numA > numB) return false;
    }
    return false; // 如果所有部分都相等，则认为 A 不大于 B
  }
  // 计算任务的进度
  function calculateTaskProgress(task) {
    let startDate: any = new Date(task.start_date),
      endDate: any = new Date(task.end_date),
      nowDate: any = new Date();
    const totalDuration = (endDate - startDate) / (1000 * 60 * 60 * 24); // 总持续天数
    const elapsedDuration = (nowDate - startDate) / (1000 * 60 * 60 * 24); // 已过天数
    if (elapsedDuration > totalDuration) {
      return '100%';
    } else if (elapsedDuration > 0) {
      const progress = (elapsedDuration / totalDuration) * 100;
      return `${parseFloat(progress.toFixed(2)).toFixed(2)}%`; // 返回百分比
    } else {
      return '0%';
    }
  
  }
  
  /**
   * 根据给定的 target 找到所有相关的 source，并递归地找出所有相关联的节点，直到没有更多的节点为止。最终返回一个新的数组。
   * @param {*} links
            * @param {*} target
            * @returns
            */
  function findRelatedLinks(links, target) {
    const result = [];
  
    function search(target) {
      // 查找所有以当前 target 为 source 的链接
      const relatedLinks = links.filter(link => link.source === target);
  
      // 将找到的链接添加到结果数组中
      relatedLinks.forEach(link => {
        if (!result.includes(link)) {
          result.push(link);
          search(link.target); // 递归查找下一个 target
        }
      });
    }
    search(target);
    return result;
  }
  
  const calculateTaskEndDate = (latestEndDate: number, duration: number, scaleUnit: string) => {
    let days = duration * 3600000;
    if (scaleUnit === 'day') {
      days *= 24;
    }
    return latestEndDate + days;
  };
  
  const onTaskChange = () => {
    gantt.attachEvent("onAfterTaskUpdate", function (id, item) {
      let links = gantt.getLinks();
      const relatedLinks = findRelatedLinks(links, id)
      refreshTaskList(id, relatedLinks)
    });
  };
  const handleTime = (time: string) => {
    if (time) {
      let parts = time.split(' ')[0].split('-');
      return parts[2] + '-' + parts[1] + '-' + parts[0];
    }
  };
  // 遍历甘特图数据
  const refreshTaskList = (id: string, linkData: any) => {
    let taskList: any = [];
    let data = gantt.serialize().data
    // console.log('重新获取的GANTT', data)
    taskList = data.map(itemTask => { // 遍历甘特图节点
      // console.log('itemTask', itemTask)
      itemTask.adjustFinishTime = new Date(handleTime(itemTask.adjustFinishTime))
      if(itemTask.parent === '0'){
        // console.log('执行次数', itemTask.text)
            let children = gantt.getChildren(itemTask.id)
            // console.log('children', children)
            if(children.length > 0){
              let last = gantt.getTask(children[children.length - 1])
              // console.log('last', last)
              itemTask.adjustFinishTime = last.adjustFinishTime
            }
          }
      linkData.map(linkItem => {
        let sourceTask = gantt.getTask(linkItem.source)
        let targetTask = gantt.getTask(linkItem.target)
        // console.log('关联来源task',sourceTask, targetTask)
        let end_date = sourceTask.end_date?.getTime() || new Date().getTime();// 当前更新的任务结束时间
        let finish_date = sourceTask.adjustFinishTime.getTime() || new Date().getTime();// 当前更新的任务完成时间
        let latestEndDate = end_date;
        let latestFinishDate = finish_date;
        let taskEndDate = calculateTaskEndDate(latestEndDate, itemTask.duration, scaleUnitModal.value);
        let taskFinishDate = calculateTaskEndDate(latestFinishDate, itemTask.duration, scaleUnitModal.value);
        let startDate = new Date(latestEndDate);
        let endDate = new Date(taskEndDate);
        let finishDate = new Date(taskFinishDate);
        // console.log('实际完成时间', finishDate)
        targetTask.start_date = startDate
        targetTask.end_date = endDate
        targetTask.adjustFinishTime = finishDate
        // console.log('link的target找到的task', targetTask)
        if (itemTask.id == linkItem.target) { // 找到当前操作的任务
          // console.log('找到当前操作的任务', itemTask, targetTask)
          itemTask = targetTask
        }
      })
      openTasks.value.map(list => {
        if (itemTask.id == list) {
          itemTask.open = true
        } else {
          itemTask.open = false
        }
      })
      return itemTask
    })
    // console.log('taskList', taskList)
    let tasks = {
      data: taskList,
      links: gantt.getLinks()
    }
    // gantt.clearAll()
    gantt.parse(tasks)
    gantt.render();
    const taskElement = document.querySelector(`[data-task-id="${id}"]`);
    // console.log('test===', scrollTop.value)
    if (taskElement) {
      const rect = taskElement.getBoundingClientRect();
      const height = gantt.getTaskTop(id);
  
      // console.log('height', height)
      const x = rect.left;
      const y = rect.top;
      // console.log(4444, rect, x, y, scrollTop.value)
      gantt.scrollTo(x, scrollTop.value);
    }
  };
  // switcha按钮事件
  const changeSwitch = (value: any) => {
    collapse.value = value
    if (collapse.value) {
      collapseAll()
    } else {
      expandAll()
    }
  }
  // 折叠所有节点
  function collapseAll() {
    gantt.eachTask(function (task) {
      task.$open = false;
    });
    gantt.render();
  
  }
  // 展开所有节点
  function expandAll() {
    gantt.eachTask(function (task) {
      task.$open = true;
    });
    gantt.render();
  }
  // 灯箱弹框设置
  const lightboxSection = () => {
    gantt.i18n.setLocale({
      labels: {
        section_progress: "进度",
        section_resourcesName: "资源",
        section_parent: "父级节点",
        section_predecessors: '前置任务'
      }
    });
    gantt.config.lightbox.sections = [
  
      { name: 'type', type: 'typeselect', map_to: 'type' },
      { name: 'time', type: 'duration', map_to: 'auto' },
      {
        name: "parent", type: "parent", allow_root: "true", root_label: "No parent", filter: function (id, task) {
          return true;
        }
      },
      {
        name: 'progress',
        height: 30,
        map_to: 'progress',
        type: 'select',
        options: [
          { key: '0', label: '未开始' },
          { key: '0.5', label: '进行中' },
          { key: '1', label: '已完成' },
        ],
      },
      {
        name: "predecessors", type: "text", allow_root: "true", template: function (task) {
          // console.log('新增是', task)
        }
      },
      {
        name: "resourcesName", type: "resources", map_to: "usage", options: [
          { key: 1, label: "10" },
          { key: 2, label: "20" },
          { key: 3, label: "30" }
        ]
      },
  
    ];
  }
  // 行编辑资源自定义事件
  // const customEditor = () => {
  //   gantt.config.editor_types.multiselect_editor = {
  //     show: function (id, column, config, placeholder) {
  //       let html = "<select multiple style='z-index:999;width:100%;'>";
  
  //       const options = resourceOption.value;
  //       options.forEach(function (option) {
  //         html += "<option value='" + option.key + "'>" + option.label + "</option>";
  //       })
  
  //       html += "</select>";
  //       placeholder.innerHTML = html;
  //     },
  //     hide: function () {
  //     },
  
  //     set_value: function (value, id, column, node) {
  //       const options = node.firstChild.childNodes;
  //       let values = [];
  
  //       if (value) {
  //         values = value.split(',');
  //       }
  
  //       values.forEach(function (selectedValue) {
  //         options.forEach(function (option) {
  //           if (option.value == selectedValue) {
  //             option.selected = true
  //           }
  //         })
  //       })
  //     },
  
  //     get_value: function (id, column, node) {
  //       const values = [];
  //       const options = node.firstChild.childNodes;
  
  //       options.forEach(function (option) {
  //         if (option.selected) values.push(option.value)
  //       })
  //       return values.join();
  //     },
  
  //     is_changed: function (value, id, column, node) {
  //       let currentValue = this.get_value(id, column, node);
  //       return value != currentValue
  //     },
  
  //     is_valid: function (value, id, column, node) {
  //       return true;
  //     },
  
  //     save: function (id, column, node) {
  //     },
  //     focus: function (node) {
  //     }
  //   }
  // }
  
  // 新增任务类型定义
  const addTaskType = () => {
    gantt.attachEvent("onTaskCreated", function (task) {
      task.type = 'task';
      task.status = '进行中';
      task.adjustFinishTime = task.end_date;
      if (task.parent !== undefined && task.parent !== '0') {
        let parentTask = gantt.getTask(task.parent)
        parentTask.type = 'project'
      }
      return true;
    });
  }
  // 初始化扩展设置
  const initExtensions = () => {
    const zoomConfig = {
      levels: [
        {
          name: "hour",
          scale_height: 50,
          // min_column_width: 120,
          scales: [
            { unit: "day", format: "%d" },
            { unit: "hour", format: "%H" },
          ]
        },
        {
          name: "day",
          scale_height: 50,
          // min_column_width: 120,
          scales: [
            { unit: "day", step: 1, format: "%d %M" }
          ]
        },
        {
          name: "week",
          scale_height: 50,
          // min_column_width: 50,
          scales: [{
            unit: "week", step: 1, format: function (date) {
              const dateToStr = gantt.date.date_to_str("%d %M");
              const endDate = gantt.date.add(date, 7 - date.getDay(), "day")
              const weekNum = gantt.date.date_to_str("%W")(date);
              return "#" + weekNum + ", " + dateToStr(date) + " - " + dateToStr(endDate);
            }
          },
          {
            unit: "day",
            step: 1,
            format: "%j %D"
          }]
        },
        {
          name: "month",
          scale_height: 50,
          // min_column_width: 120,
          scales: [
            { unit: "month", format: "%F, %Y" },
            { unit: "week", format: "Week #%W" }
          ]
        },
        {
          name: "quarter",
          height: 50,
          // min_column_width: 90,
          scales: [
            {
              unit: "quarter", step: 1, format: function (date) {
                const dateToStr = gantt.date.date_to_str("%M");
                const endDate = gantt.date.add(date, 2 - date.getMonth() % 3, "month");
                return dateToStr(date) + " - " + dateToStr(endDate);
              }
            },
            { unit: "month", step: 1, format: "%M" },
          ]
        },
        {
          name: "year",
          scale_height: 50,
          // min_column_width: 30,
          scales: [
            { unit: "year", step: 1, format: "%Y" }
          ]
        }
      ],
      useKey: "ctrlKey",
      trigger: "wheel",
      element: function () {
        // return gantt.$root.querySelector(".gantt_task");
      }
    };
    gantt.ext.zoom.init(zoomConfig);
  }
  // 拖动改变顺序事件
  const dragOrder = () => {
    gantt.attachEvent("onBeforeRowDragEnd", function (id, parent, tindex) {
      const task = gantt.getTask(id);
      if (parent !== task.parent) {
        gantt.confirm({
          text: "确定要更改任务位置吗?",
          ok: "是",
          cancel: "否",
          callback: function (result) {
            // Don't do anything for "No"
            // Move to the new parent for "Yes"
            if (result) {
              gantt.moveTask(id, tindex, parent);
            }
          }
        });
        return false;
      }
      return true
    });
  }
  // 复选框选中数据处理
  const handleCheckboxChange = (event: Event) => {
    const targetCheckbox = event.target as HTMLInputElement;
    const targetId = targetCheckbox.id.includes('project')
      ? targetCheckbox.id.substring(15) // 任务id for project checkboxes
      : targetCheckbox.id.substring(12); // 任务id for other checkboxes
  
    const ganttChildren = gantt.getChildren(targetId);
    // console.log('选中项目的子级', ganttChildren)
    const isChecked = targetCheckbox.checked;
    let updatedCheckList = [...checkList.value];
  
    // 如果选中，添加当前id及子任务id到checkList
    if (isChecked) {
      updatedCheckList.push(targetId);
      ganttChildren.forEach(childId => {
        const childCheckbox = document.getElementById('checkboxtask' + childId);
        if (childCheckbox) {
          childCheckbox.checked = true;
          updatedCheckList.push(childId);
        }
      });
    } else {
      // 如果未选中，移除当前id及子任务id from checkList
      updatedCheckList = updatedCheckList.filter(id => id !== targetId && !ganttChildren.includes(id));
      ganttChildren.forEach(childId => {
        const childCheckbox = document.getElementById('checkboxtask' + childId);
        if (childCheckbox) {
          childCheckbox.checked = false;
        }
      });
    }
  
    // 更新checkList状态
    checkList.value = updatedCheckList;
    // console.log('最后选中的', checkList.value)
  };
  // 导出gantt图PDF
  function exportData(name: String, headerTitle: String, type: String) {
    // A4: 297 计算页面高度（像素）
    const pageHeight = 297 / 25.4 * 98;
    // PDF以点为单位进行测量，高度四舍五入
    // 您需要计算将剪切或添加多少像素
    // 根据页面大小
    let increaseHeight = pageHeight - parseInt(pageHeight);
    increaseHeight -= 1;
    const gridHeaderHeight = gantt.$grid_scale.getBoundingClientRect().height;
  
    let iteratedHeight = gridHeaderHeight;
  
    let page = 1;
    let previousHeight, lastParent, lastIndex;
  
    // add empty rows
    gantt.batchUpdate(function () {
      gantt.eachTask(function (task) {
        const taskHeight = gantt.getTaskHeight(task.id);
        iteratedHeight += taskHeight;
  
        const diff = iteratedHeight - pageHeight * page;
        if (diff > 0) {
          const newId = gantt.uid() + task.id + "_empty_row";
          let rowFill = pageHeight * page - previousHeight;
  
          lastParent = task.parent;
          lastIndex = gantt.getTaskIndex(task.id)
  
          gantt.addTask({ id: newId, empty_row: true, $virtual: true, row_height: rowFill, unscheduled: true }, lastParent, lastIndex)
          iteratedHeight += rowFill + increaseHeight;
          page++
          // console.log(task.text)
        }
        if (diff === 0) {
          page++
        }
        previousHeight = iteratedHeight;
      })
    });
  
    // shrink the timeline before export
    const initialZoomLevel = gantt.ext.zoom.getCurrentLevel();
    const initialScrollPos = gantt.getScrollState();
    // console.log('gantt.ext.zoom', gantt.ext.zoom.setLevel("day"))
    gantt.ext.zoom.setLevel("day");
  
    gantt.exportToPDF({
      name: name,
      header: headerTitle,
      // raw: true,
      additional_settings: {
        merge_pages: true,
        // format: 'A4'
      }
    });
  
    // restore previous zoom level
    gantt.ext.zoom.setLevel(initialZoomLevel);
  
    // scroll to the previous position
    gantt.scrollTo(initialScrollPos.x, null);
  
    // remove empty task rows
    gantt.batchUpdate(function () {
      gantt.eachTask(function (task) {
        if (task.empty_row) {
          gantt.deleteTask(task.id)
        }
      })
    });
  }
  onBeforeUnmount(() => {
    gantt.clearAll()
  })
  // 新建节点
  const addTask = () => {
    let id = generateUUID();
    let days = 1 * 3600000 * 24;
    let sdata = new Date().getTime();
    let end = sdata + days;
    let child = gantt.getChildren(0);
    let taskInfo = {
      duration: 1,
      id: id,
      open: false,
      text: '新节点',
      type: 'task',
      start_date: new Date(sdata),
      end_date: new Date(end),
      adjustFinishTime: new Date(end),
      isNew: true,
      status: '进行中',
    };
    gantt.addTask(taskInfo, 0, child.length);
  };
  // 刷新前进后退按钮状态
  function refreshUndoBtns() {
    if (!gantt.getUndoStack || !gantt.getUndoStack().length) {
      undoDisabled.value = true;
    } else {
      undoDisabled.value = false;
    }
  
    if (!gantt.getRedoStack || !gantt.getRedoStack().length) {
      redoDisabled.value = true;
    } else {
      redoDisabled.value = false;
    }
  }
  //后退
  const undoAction = () => {
    // 可以后退 新增，删除，修改
    gantt.undo();
    refreshUndoBtns()
  };
  // 前进
  const ReDoAction = () => {
    gantt.redo();
    refreshUndoBtns()
  };
  // 删除任务
  const deleteTasks = () => {
    // console.log('delete', checkList.value)
    let deleteChildren = [] as any;
    let deleteParent = [] as any;
    checkList.value.forEach((id: any) => {
      let task = gantt.getTask(id);
      if (task.parent !== undefined) {
        deleteChildren.push(id)
      } else {
        deleteParent.push(id)
      }
    });
    // console.log('deleteChildren', deleteChildren)
    // console.log('deleteParent', deleteParent)
    if (deleteChildren.length > 0) {
      // 先删除子任务
      deleteChildren.forEach((id: any) => {
        gantt.deleteTask(id)
      })
    }
    if (deleteParent.length > 0) {
      // 删除父任务 project
      deleteParent.forEach((id: any) => {
        let otherChild = gantt.getChildren(id)
        // console.log('otherChild', otherChild)
        if (otherChild.length !== 0 && JSON.stringify(deleteChildren) !== JSON.stringify(otherChild)) {  // 判断父级任务是否还有子任务
            ElMessage.error('父级任务下还有子任务，无法删除！')
        } else {
          let links: any = gantt.getLinks();
          let findlinks = links.filter((link: any) => link.source + '' === id + '');
          // console.log(22, findlinks)
          // 找出已有的关联关系
          findlinks.forEach((f: any) => {
            // console.log('f', f)
            gantt.deleteLink(f.id);
          });
          // console.log('id', id)
          gantt.deleteTask(id)
        }
      })
    }
    checkList.value = []
  };
  // 建立连接按钮事件
  const addLinks = () => {
    let tasks = [] as any;
    let sourceId = '';
    let updateTask = [] as any;
    let linkDate = new Date().getTime();
    let links: any = gantt.getLinks();
    gantt.eachTask((task: any) => {
      const findIndex = checkList.value.findIndex((c: String) => c === task.id + '');
      if (findIndex > -1) {
        if (!sourceId) {
          sourceId = task.id;
          linkDate = task.end_date.getTime();
        } else {
          const findIndexs = links.findIndex((link: any) => link.target + '' === task.id + '' && link.source + '' === sourceId + '');
          if (findIndexs < 0) {
            tasks.push({
              id: generateUUID(),
              source: sourceId,
              target: task.id,
              type: gantt.config.links.finish_to_start,
            });
            let taskEndDate = new Date().getTime();
            if (existEditType.value === 'day') {
              let days = task.duration * 3600000 * 24;
              taskEndDate = linkDate + days;
            } else {
              let days = task.duration * 3600000;
              taskEndDate = linkDate + days;
            }
            let taskInfo = {
              duration: task.duration,
              id: task.id,
              open: task.open,
              parent: task.parent,
              text: task.text,
              type: task.type,
              color: task.color,
              start_date: new Date(linkDate),
              end_date: new Date(taskEndDate),
              adjustFinishTime: new Date(taskEndDate),
            };
            updateTask.push(taskInfo);
            linkDate = taskEndDate;
            sourceId = task.id;
          }
        }
      }
    });
    if (tasks.length > 0) {
      isNotReset.value = true;
      tasks.forEach((task: any) => {
        gantt.addLink(task);
      });
    }
  };
  // 对选中数据要做的操作进行判断
  const checkAction = (type) => {
    var action = actions[type]
    // console.log(111, actions, type)
    if (!action)
      return;
    gantt.batchUpdate(function () {
      let indexes = {};
      let siblings = {};
      let updated = {};
      checkList.value.forEach((task_id: any) => {
        indexes[task_id] = gantt.getTaskIndex(task_id);
        siblings[task_id] = {
          first: null
        };
        // console.log(99, indexes, siblings)
        var currentId = task_id;
        while (gantt.isTaskExists(gantt.getPrevSibling(currentId)) && gantt.isSelectedTask(gantt.getPrevSibling(currentId))) {
          currentId = gantt.getPrevSibling(currentId);
        }
        siblings[task_id].first = currentId;
        var prev_id = gantt.getPrevSibling(task_id);
        while (gantt.isSelectedTask(prev_id)) {
          var prev = gantt.getPrevSibling(prev_id);
          if (!prev) break;
          prev_id = prev;
        }
        siblings[task_id].first = currentId;
        if (!updated[gantt.getParent(task_id)]) {
          var updated_id = action(task_id, indexes, siblings);
          updated[updated_id] = true;
        } else {
          updated[task_id] = true;
        }
      })
    })
  }
  /**
   * 任务插入
   * @param {*}
            *
            */
  const addAction = (type: String) => {
    let task: any = gantt.getTask(checkList.value[0]);
    if (task && task.progress == 1) {
        ElMessage.error('已完成节点无法插入和复制');
      return;
    }
    let child = gantt.getChildren(task.parent);
    let links: any = gantt.getLinks();
    const findIndex = child.findIndex((f) => f === task.id);
    let id = generateUUID();
    let taskInfo = {
      duration: task.duration,
      id: id,
      open: task.open,
      parent: task.parent,
      // progress: task.progress,
      text: task.text,
      type: task.type,
      start_date: task.start_date,
      end_date: task.end_date,
      adjustFinishTime: task.adjustFinishTime,
      isNew: true,
    };
    if (type !== 'copy') {
      taskInfo.text = '空白任务';
    }
    gantt.addTask(taskInfo, task.parent, findIndex);
    let findlinks = links.filter((link: any) => link.source + '' === task.id + '');
    if (findlinks.length > 0 && type !== 'copy') {
      let link = {
        id: generateUUID(),
        source: id,
        target: task.id,
        type: gantt.config.links.finish_to_start,
      };
      isNotReset.value = true;
      gantt.addLink(link);
    }
  };
  // 获取甘特图数据发送给父组件
  const getGanttData = () => {
    let data = gantt.serialize(); // 获取数据(包括data，links)
    // console.log('甘特图数据==》', data)
    return {
      ...data,
      editType: gantt.config.duration_unit,
    };
  }
  // 甘特图选中的任务
  const getGanttCheckedTask = () => {
    return checkList.value
  }
  defineExpose({
    getGanttInfo,
    exportData,
    getGanttData,
    getGanttCheckedTask
  })
  </script>
  
  <style>
  @import 'dhtmlx-gantt/codebase/dhtmlxgantt.css';
  
  .gantt_row[data-task-id*="empty_row"] {
    visibility: hidden;
  }
  
  .gantt_marker.today {
    background: #ffb121;
  }
  
  .status_line {
    background-color: #0ca30a;
  }
  </style>
  